﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using VAdvantage.Classes;
using VAdvantage.Common;
using VAdvantage.Process; using VAdvantage.ProcessEngine;
using VAdvantage.Model;
using VAdvantage.DataBase;
using VAdvantage.SqlExec;
using VAdvantage.Utility;
using VAdvantage.Controls;
using System.Data;
using System.Data.SqlClient;
using VAdvantage.Logging;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Threading;

namespace VAdvantage.Grids
{
    public class VCreateFromInvoice : VCreateFrom
    {
        #region Private Vaiables

        private static long serialVersionUID = 1L;
        private bool _actionActive = false;
        private MInOut _inout = null;
        DataSet _mainDataSet = null;
        //	Static Logger	
        private static VLogger _log = VLogger.GetVLogger(typeof(VCreateFromInvoice).FullName);

        #endregion

        /// <summary>
        /// Default constructor
        /// </summary>
        public VCreateFromInvoice()
            : base()
        {
        }

        /// <summary>
        /// Protected Constructor
        /// </summary>
        /// <param name="mTab">MTab</param>
        public VCreateFromInvoice(GridTab mTab)
            : base(mTab)
        {
            _log.Info(mTab.ToString());
            this.cmbShipment.SelectionChanged += new SelectionChangedEventHandler(cmbShipment_SelectionChanged);
            this.cmbOrder.SelectionChanged += new SelectionChangedEventHandler(cmbOrder_SelectionChanged);
            
        }

        /// <summary>
        /// Dynamic Init
        /// </summary>
        /// <returns>true if initialized</returns>
        protected override bool DynInit()
        {
            _log.Config("");
            // SetTitle(Msg.GetElement(Envs.GetContext(), "C_Invoice_ID", false) + " .. " + Msg.Translate(Envs.GetContext(), "CreateFrom"));
            this.Title = Msg.GetElement(Envs.GetContext(), "C_Invoice_ID", false) + " .. " + Msg.Translate(Envs.GetContext(), "CreateFrom");
            //parameterBankPanel.setVisible(false);
            lblInvoice.Visible = false;
            cmbInvoice.Visible = false;
            lblLocator.Visible = false;
            locatorField.Visible = false;

            InitBPartner(true);
            return true;
        }

        /// <summary>
        /// Get list of invoices for a particular business partner
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="C_BPartner_ID"></param>
        /// <returns></returns>
        public static List<NamePair> GetShipments(Context ctx, int C_BPartner_ID)
        {
            List<NamePair> pairs = new List<NamePair>();

            //	Display
            StringBuilder display = new StringBuilder("s.DocumentNo||' - '||")
                .Append(DB.TO_CHAR("s.MovementDate", DisplayType.Date, Envs.GetAD_Language(Envs.GetContext())));
            //
            StringBuilder sql = new StringBuilder("SELECT s.M_InOut_ID,").Append(display)
                .Append(" FROM M_InOut s "
                + "WHERE s.C_BPartner_ID=" + C_BPartner_ID + " AND s.IsSOTrx='N' AND s.DocStatus IN ('CL','CO')"
                + " AND s.M_InOut_ID IN "
                    + "(SELECT sl.M_InOut_ID FROM M_InOutLine sl"
                    + " LEFT OUTER JOIN M_MatchInv mi ON (sl.M_InOutLine_ID=mi.M_InOutLine_ID) "
                    + "GROUP BY sl.M_InOut_ID,mi.M_InOutLine_ID,sl.MovementQty "
                    + "HAVING (sl.MovementQty<>SUM(mi.Qty) AND mi.M_InOutLine_ID IS NOT NULL)"
                    + " OR mi.M_InOutLine_ID IS NULL) "
                + "ORDER BY s.MovementDate");
            DataTable dt = null;
            IDataReader idr = null;
            try
            {
                idr = DB.ExecuteReader(sql.ToString(), null, null);
                dt = new DataTable();
                dt.Load(idr);
                idr.Close();
                foreach (DataRow dr in dt.Rows)// while (dr.next())
                {
                    pairs.Add(new KeyNamePair(Util.GetValueOfInt(dr[0].ToString()), dr[1].ToString()));
                }
            }
            catch (Exception e)
            {
                idr.Close();
                _log.Log(Level.SEVERE, sql.ToString(), e);
            }
            finally
            {
                dt = null;
                if (idr != null)
                {
                    idr.Close();
                }
            }
            return pairs;
        }

        /// <summary>
        /// Init Details - load receipts not invoiced
        /// </summary>
        /// <param name="C_BPartner_ID">BPartner</param>
        protected override void InitBPDetails(int C_BPartner_ID, List<NamePair> invoice, List<NamePair> shipments)
        {
            _log.Config("C_BPartner_ID" + C_BPartner_ID);

            //  load Shipments (Receipts) - Completed, Closed
            cmbShipment.Items.Clear();
            //	None
            KeyNamePair pp = new KeyNamePair(0, "");
            cmbShipment.Items.Add(pp);

            foreach (NamePair pair in shipments)
            {
                cmbShipment.Items.Add(pair);
            }
            cmbShipment.SelectedIndex = 0;
        }

        /// <summary>
        /// Load Data - Shipment not invoiced
        /// </summary>
        /// <param name="M_InOut_ID">MInout</param>
        private void LoadShipment(int M_InOut_ID)
        {
            _log.Config("M_InOut_ID=" + M_InOut_ID);
            ThreadPool.QueueUserWorkItem(delegate
           {
               _inout = new MInOut(Envs.GetContext(), M_InOut_ID, null);
               _order = null;
               if (_inout.GetC_Order_ID() != 0)
               {
                   _order = new MOrder(Envs.GetContext(), _inout.GetC_Order_ID(), null);
               }
               DataSet data = GetShipmentData(Envs.GetContext(), M_InOut_ID);
               System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => BindGrid(data, 0, M_InOut_ID, false));
               //LoadTableOIS(data);
           });
        }

        /// <summary>
        /// Get the table data for a particular shipment
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="M_InOut_ID"></param>
        /// <returns></returns>
        public static DataSet GetShipmentData(Context ctx, int M_InOut_ID)
        {
            StringBuilder sql = new StringBuilder("SELECT " // QtyEntered
                    + "(l.MovementQty-SUM(NVL(mi.Qty,0))) * (l.QtyEntered/l.MovementQty) as QUANTITY ,"
                    + " l.C_UOM_ID as C_UOM_ID,COALESCE(uom.UOMSymbol,uom.Name) as UOM ," // 3..4
                    + " l.M_Product_ID as M_PRODUCT_ID ,p.Name as PRODUCT , l.M_InOutLine_ID as M_INOUTLINE_ID,l.Line as LINE," // 5..8
                    + " l.C_OrderLine_ID as C_ORDERLINE_ID,'false' as SELECTROW  "); // 9

            if (Envs.IsBaseLanguage(ctx, "C_UOM"))
            {
                sql.Append(" FROM C_UOM uom ").Append("INNER JOIN M_InOutLine l ON (l.C_UOM_ID=uom.C_UOM_ID) ");
            }
            else
            {
                // nnayak : Fix for bug 1722916
                sql.Append("FROM C_UOM_Trl uom ").Append(
                        "INNER JOIN M_InOutLine l ON (l.C_UOM_ID=uom.C_UOM_ID AND uom.AD_Language='").Append(
                        Envs.GetAD_Language(ctx)).Append("') ");
            }
            sql.Append("INNER JOIN M_Product p ON (l.M_Product_ID=p.M_Product_ID) ").Append(
                    "LEFT OUTER JOIN M_MatchInv mi ON (l.M_InOutLine_ID=mi.M_InOutLine_ID) ").Append("WHERE l.M_InOut_ID=" + M_InOut_ID) // #1
                    .Append(
                            "GROUP BY l.MovementQty,l.QtyEntered/l.MovementQty," + "l.C_UOM_ID,COALESCE(uom.UOMSymbol,uom.Name),"
                                    + "l.M_Product_ID,p.Name, l.M_InOutLine_ID,l.Line,l.C_OrderLine_ID ").Append("ORDER BY l.Line");
            DataSet ds = null;
            try
            {
                ds = DB.ExecuteDataset(sql.ToString(), null);
            }
            catch (Exception e)
            {
                _log.Log(Level.SEVERE, sql.ToString(), e);
            }
            return ds;
        }

        /// <summary>
        /// List number of rows selected
        /// </summary>
        protected override void Info()
        {
            int rows = _mainDataSet.Tables[0].Rows.Count;
            int count = 0;
            for (int i = 0; i < rows; i++)
            {
                //if (Convert.ToBoolean((Boolean)Model.Rows[i].Cells[0].Value))
                if (Convert.ToBoolean(_mainDataSet.Tables[0].Rows[i][0]))
                {
                    count++;
                }
            }
            base.statusBar.SetStatusLine(count.ToString());
            gridCount = count;
        }

        /// <summary>
        /// Save - Create Invoice Lines
        /// </summary>
        /// <returns>true if saved</returns>
        protected override bool Save()
        {
            base.btnOk.IsEnabled = false;
            _log.Config("");
            //IList list = base.vdgvRecords.SelectedItems;
            //  Invoice
            int C_Invoice_ID = Convert.ToInt32(_mTab.GetValue("C_Invoice_ID"));
            //return SaveData(Envs.GetContext(), list, _order, _inout, C_Invoice_ID);
            base.statusBar.SetStatusLine(Msg.GetMsg(Envs.GetCtx(), "NumberOfRows") + mainDataSet.Tables[0].Rows.Count.ToString());
            ThreadPool.QueueUserWorkItem(delegate
       {
           SaveData(Envs.GetContext(), mainDataSet, _order, _inout, C_Invoice_ID);
           Dispatcher.BeginInvoke(delegate
           {
               base.DialogResult = true;
           });
       });
            return true;
        }

        /// <summary>
        /// Save data in c_invoice tables
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="model"></param>
        /// <param name="_order"></param>
        /// <param name="_inout"></param>
        /// <param name="C_Invoice_ID"></param>
        /// <returns></returns>
        public static bool SaveData(Context ctx, DataSet ds, MOrder _order, MInOut _inout, int C_Invoice_ID)
        {
            List<DataRow> collection = new List<DataRow>();
            if (ds != null)
            {
                for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
                {
                    if (ds.Tables[0].Rows[i]["SELECTROW"].ToString().ToUpper() == "TRUE")
                    {
                        collection.Add(ds.Tables[0].Rows[i]);
                    }
                }
            }
            else
            {
              
                return false;
            }

            //int rows = ds.Tables[0].Rows.Count;
            int rows = collection.Count;
            if (rows == 0)
            {
                return false;
            }
            
         
              MInvoice invoice = new MInvoice(ctx, C_Invoice_ID, null);
              _log.Config(invoice.ToString());
              if (_order != null)
              {
                  invoice.SetOrder(_order);	//	overwrite header values
                  invoice.Save();
              }
              if (_inout != null && _inout.GetM_InOut_ID() != 0
                  && _inout.GetC_Invoice_ID() == 0)	//	only first time
              {
                  _inout.SetC_Invoice_ID(C_Invoice_ID);
                  _inout.Save();
              }

              //  Lines
              for (int i = 0; i < rows; i++)
              {
                  //if ((Boolean)Model.Rows[i].Cells[0].Value)
                  if (true)// if (Convert.ToBoolean(((BindableObject)list[i]).GetValue("SELECT")))
                  {
                      //  variable values
                      double d = Convert.ToDouble(collection[i].ItemArray["QUANTITY"].Value);           //  1-Qty
                      Decimal QtyEntered = Convert.ToDecimal(d);
                      //KeyNamePair pp = (KeyNamePair)dt.Rows[i][2];   //  2-UOM
                      //int C_UOM_ID = pp.GetKey();
                      int C_UOM_ID = Util.GetValueOfInt(collection[i].ItemArray["C_UOM_ID"].Value);   //  2-UOM
                      //
                      // pp = (KeyNamePair)dt.Rows[i][3];               //  3-Product
                      int M_Product_ID = 0;
                      // if (pp != null)
                      {
                          M_Product_ID = Util.GetValueOfInt(collection[i].ItemArray["M_PRODUCT_ID"].Value); //  3-Product
                      }
                      int C_OrderLine_ID = 0;
                      int M_InOutLine_ID = 0;
                      try
                      {
                          M_InOutLine_ID = Util.GetValueOfInt(collection[i].ItemArray["M_INOUTLINE_ID"].Value);
                      }
                      catch (Exception ex)
                      {
                          _log.SaveError("M_INOUTLINE_ID", ex);
                      }
                      try
                      {
                          C_OrderLine_ID = Util.GetValueOfInt(collection[i].ItemArray["C_ORDERLINE_ID"].Value);//  4-OrderLine
                      }
                      catch (Exception ex)
                      {
                          _log.SaveError("C_ORDERLINE_ID", ex);
                      }
                      //	Precision of Qty UOM
                      int precision = 2;
                      if (M_Product_ID != 0)
                      {
                          MProduct product = MProduct.Get(ctx, M_Product_ID);
                          precision = product.GetUOMPrecision();
                      }
                      QtyEntered = Decimal.Round(QtyEntered, precision);

                      _log.Fine("Line QtyEntered=" + QtyEntered
                          + ", Product_ID=" + M_Product_ID
                          + ", OrderLine_ID=" + C_OrderLine_ID + ", InOutLine_ID=" + M_InOutLine_ID);

                      //	Create new Invoice Line
                      MInvoiceLine invoiceLine = new MInvoiceLine(invoice);
                      invoiceLine.SetM_Product_ID(M_Product_ID, C_UOM_ID);	//	Line UOM
                      invoiceLine.SetQty(QtyEntered);							//	Invoiced/Entered
                      //  Info
                      MOrderLine orderLine = null;
                      if (C_OrderLine_ID != 0)
                          orderLine = new MOrderLine(ctx, C_OrderLine_ID, null);
                      MInOutLine inoutLine = null;
                      if (M_InOutLine_ID != 0)
                      {
                          inoutLine = new MInOutLine(ctx, M_InOutLine_ID, null);
                          if (orderLine == null && inoutLine.GetC_OrderLine_ID() != 0)
                          {
                              C_OrderLine_ID = inoutLine.GetC_OrderLine_ID();
                              orderLine = new MOrderLine(ctx, C_OrderLine_ID, null);
                          }
                      }
                      else
                      {
                          MInOutLine[] lines = MInOutLine.GetOfOrderLine(ctx, C_OrderLine_ID, null, null);
                          _log.Fine("Receipt Lines with OrderLine = #" + lines.Length);
                          if (lines.Length > 0)
                          {
                              for (int j = 0; j < lines.Length; j++)
                              {
                                  MInOutLine line = lines[j];
                                  if (line.GetQtyEntered().CompareTo(QtyEntered) == 0)
                                  {
                                      inoutLine = line;
                                      M_InOutLine_ID = inoutLine.GetM_InOutLine_ID();
                                      break;
                                  }
                              }
                              if (inoutLine == null)
                              {
                                  inoutLine = lines[0];	//	first as default
                                  M_InOutLine_ID = inoutLine.GetM_InOutLine_ID();
                              }
                          }
                      }	//	get Ship info

                      //	Shipment Info
                      if (inoutLine != null)
                      {
                          invoiceLine.SetShipLine(inoutLine);		//	overwrites
                          if (inoutLine.GetQtyEntered().CompareTo(inoutLine.GetMovementQty()) != 0)
                          {
                              invoiceLine.SetQtyInvoiced(Decimal.Round(Decimal.Divide(Decimal.Multiply(QtyEntered,
                              inoutLine.GetMovementQty()),
                              inoutLine.GetQtyEntered()), 12));
                          }
                      }
                      else
                      {
                          _log.Fine("No Receipt Line");
                      }

                      //	Order Info
                      if (orderLine != null)
                      {
                          invoiceLine.SetOrderLine(orderLine);	//	overwrites

                          /* The organization from the Orderline can be different from the organization 
                          on the header */
                          invoiceLine.SetClientOrg(orderLine.GetAD_Client_ID(), orderLine.GetAD_Org_ID());
                          if (orderLine.GetQtyEntered().CompareTo(orderLine.GetQtyOrdered()) != 0)
                          {
                              invoiceLine.SetQtyInvoiced(Decimal.Round(Decimal.Divide(Decimal.Multiply(QtyEntered,
                              orderLine.GetQtyOrdered()),
                              orderLine.GetQtyEntered()), 12));
                          }
                      }
                      else
                      {
                          _log.Fine("No Order Line");

                          /* The organization from the Receipt can be different from the organization 
                          on the header */
                          if (inoutLine != null)
                          {
                              invoiceLine.SetClientOrg(inoutLine.GetAD_Client_ID(), inoutLine.GetAD_Org_ID());
                          }

                          invoiceLine.SetPrice();
                          invoiceLine.SetTax();
                      }
                      if (!invoiceLine.Save())
                      {
                          _log.Log(Level.SEVERE, "Line NOT created #" + i);
                      }
                  }   //   if selected
              }   //  for all rows
         // });
            return true;
        }

        void cmbOrder_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //vdgvRecords.Rows.Clear();
            vdgvRecords.DataContext = null;
            vdgvRecords.ItemsSource = null;
            vdgvRecords.Columns.Clear();
            KeyNamePair pp = (KeyNamePair)cmbOrder.SelectedItem;
            int C_Order_ID = 0;
            if (pp == null || pp.GetKey() == 0)
            {
                ;
            }
            else
            {
                C_Order_ID = pp.GetKey();

                //  set Invoice and Shipment to Null
                cmbInvoice.SelectedIndex = -1;
                cmbShipment.SelectedIndex = -1;
                LoadOrder(C_Order_ID, true);
            }
        }

        private void cmbShipment_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

            //vdgvRecords.Rows.Clear();
            vdgvRecords.DataContext = null;
            vdgvRecords.ItemsSource = null;
            vdgvRecords.Columns.Clear();
            KeyNamePair pp = (KeyNamePair)cmbShipment.SelectedItem;
            int M_InOut_ID = 0;
            if (pp == null || pp.GetKey() == 0)
            {
                ;
            }
            else
            {
                M_InOut_ID = pp.GetKey();
                //  set Order and Invoice to Null
                cmbOrder.SelectedIndex = -1;
                cmbInvoice.SelectedIndex = -1;
                LoadShipment(M_InOut_ID);
            }
        }

    }
}
